package org.autoparser;

import java.io.File;
import java.util.LinkedList;
import java.util.Queue;

import org.autoparser.exttree.ZDataContainer;
import org.autoparser.exttree.ZExtTree;
import org.autoparser.exttree.ZExtTreeNode;
import org.dom4j.DocumentException;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class ZParser {
	private ZExtTree extTree;
	private boolean useFastMode;

	public ZParser(File xmlFile, boolean useFastMode) throws DocumentException {
		this.useFastMode = useFastMode;
		extTree = new ZExtTree(xmlFile);
	}

	public ZParser(File xmlFile) throws DocumentException {
		this(xmlFile, true);
	}

	private static void ExtTermInfoRecur(ZExtTreeNode byNode, Node node,
			boolean caseSensitive) {
		if ((node instanceof Tag)
				&& byNode.isTagSatisfy((Tag) node, caseSensitive)) {
			byNode.extractTerm(node);
			NodeFilter filter = byNode.getNextFilter();
			if (filter != null) {
				NodeList childs = new NodeList();
				node.collectInto(childs, filter);
				for (ZExtTreeNode treeNode : byNode.getChilds()){
					int order = 0;
					for (int i = 0; i < childs.size(); ++i){
						if((childs.elementAt(i) instanceof Tag) && treeNode.isTagSatisfy((Tag)(childs.elementAt(i)), caseSensitive)){
							++order;
							if(treeNode.getOrder() < 0 || treeNode.getOrder() == order)
								ExtTermInfoRecur(treeNode, childs.elementAt(i),caseSensitive);
						}
					}
				}
			}
		}
	}

	private void extractInfoRecur(String evetp, boolean caseSensitive)
			throws ParserException {
		Parser p = null;
		p = new Parser(evetp);
		NodeFilter filter = extTree.getNextFilter();
		if (filter != null) {
			NodeList nList = p.extractAllNodesThatMatch(filter);
			if (nList != null && nList.size() > 0) {
				for (ZExtTreeNode treeNode : extTree.getChilds()){
					int order = 0;
					for (int i = 0; i < nList.size(); ++i) {
						if((nList.elementAt(i) instanceof Tag) && treeNode.isTagSatisfy((Tag)(nList.elementAt(i)), caseSensitive)){
							++order;
							if(treeNode.getOrder() < 0 || treeNode.getOrder() == order)
								ExtTermInfoRecur(treeNode, nList.elementAt(i),caseSensitive);
						}
					}
				}
			}
		}
	}

	private static class AB {
		public Tag mTag;
		public ZExtTreeNode mTreeNode;

		public AB(Tag tag, ZExtTreeNode treeNode) {
			mTag = tag;
			mTreeNode = treeNode;
		}
	};

	private static void Offer(NodeList nList, ZExtTreeNode treeNode,
			Queue<AB> abQueue, boolean caseSensitive) {
		if (nList != null && nList.size() > 0) {
			for (ZExtTreeNode extNode : treeNode.getChilds()){
				int order = 0;
				for (int i = 0; i < nList.size(); ++i)
					if ((nList.elementAt(i) instanceof Tag)&& extNode.isTagSatisfy((Tag) nList.elementAt(i),caseSensitive)){
						++order;
						if(extNode.getOrder() < 0 || extNode.getOrder() == order)
							abQueue.offer(new AB((Tag) nList.elementAt(i), extNode));
					}
			}
		}
	}

	private void extractInfoIter(String evetp, boolean caseSensitive)
			throws ParserException {
		Queue<AB> abQueue = new LinkedList<AB>();
		Parser p = null;
		p = new Parser(evetp);
		NodeFilter filter = extTree.getNextFilter();
		NodeList nList = new NodeList();
		if (filter != null) {
			nList = p.extractAllNodesThatMatch(filter);
			Offer(nList, extTree, abQueue, caseSensitive);
		}
		while (!abQueue.isEmpty()) {
			AB ab = abQueue.poll();
			ab.mTreeNode.extractTerm(ab.mTag);
			filter = ab.mTreeNode.getNextFilter();
			if (filter != null) {
				nList.removeAll();
				ab.mTag.collectInto(nList, filter);
				Offer(nList, ab.mTreeNode, abQueue, caseSensitive);
			}
		}
	}

	public void extractInfo(String evetp, boolean caseSensitive,
			ZDataContainer datacontainer) throws ParserException {
		extTree.setDataContainer(datacontainer);
		if (useFastMode)
			extractInfoIter(evetp, caseSensitive);
		else
			extractInfoRecur(evetp, caseSensitive);
	}

	public void extractInfo(String evetp, ZDataContainer datacontainer)
			throws ParserException {
		extractInfo(evetp, false, datacontainer);
	}
	
	public boolean isUseFastMode() {
		return useFastMode;
	}

	public void setUseFastMode(boolean useFastMode) {
		this.useFastMode = useFastMode;
	}
}
